package cn.xxs.filter;


import cn.utils.StringUtils;
import cn.http.enums.HttpMethod;
import cn.xxs.build.SimpleXssFilterConfig;
import lombok.Getter;
import org.springframework.util.CollectionUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

/**
 * 类简介:XSS过滤
 *
 * @Author: ShangGuan
 * @Time: 2024/05/13
 **/
public class XssFilter implements Filter {


    @Getter
    private final SimpleXssFilterConfig xssConfig;

    public XssFilter(SimpleXssFilterConfig xssConfig) {
        if (!CollectionUtils.isEmpty(xssConfig.getExcludes())) {
            excludes = xssConfig.getExcludes();
        }
        //给includeMethod赋值
        if (!CollectionUtils.isEmpty(xssConfig.getIncludeMethod())) {
            for (String method : xssConfig.getIncludeMethod()) {
                String upperCaseMethod = method.toUpperCase();
                HttpMethod httpMethod = HttpMethod.valueOf(upperCaseMethod);
                includeMethod.put(upperCaseMethod, httpMethod);
            }
        }
        this.xssConfig = xssConfig;

    }


    /**
     * 排除链接 条件
     */
    private List<String> excludes = new ArrayList<>();

    /**
     * 包含的方法
     */
    private Map<String, HttpMethod> includeMethod = new HashMap<>();


    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        if (handleExcludeUrlAndMethod(req)) {
            // 传递过滤器
            chain.doFilter(request, response);
            return;
        }
        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request, xssConfig.getErrorMsg());
        chain.doFilter(xssRequest, response);
    }


    /**
     * 处理排除 URL 和方法
     * 方法简介: 如果不包含使用的方法就返回true，表示放行
     * 业务背景:
     *
     * @param request 请求
     * @return boolean
     **/
    private boolean handleExcludeUrlAndMethod(HttpServletRequest request) {
        String url = request.getServletPath();
        String method = request.getMethod();
        if (method == null) {
            return true;
        }
        //转化为大写
        method = method.toUpperCase();
        HttpMethod httpMethod = includeMethod.get(method);
        if (httpMethod == null) {
            return true;
        }
        boolean matches = httpMethod.matches(method);
        if (!matches) {
            return true;
        }
        return StringUtils.matches(url, excludes);
    }

    @Override
    public void destroy() {

    }


}